package cn.template.services;

import cn.template.models.BaseObject;
import cn.template.models.exceptions.DatabaseOperationException;
import cn.template.models.exceptions.NotFoundException;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.CrudRepository;


public abstract class BaseService<R extends CrudRepository<T, Long>, T extends BaseObject> {
    private R repository;

    protected R getRepository() {
        return repository;
    }

    protected void setRepository(R repository) {
        this.repository = repository;
    }

    public Iterable<T> getAll() {
        try {
            return this.repository.findAll();
        } catch (RuntimeException ex) {
            throw new DatabaseOperationException("Fail to query all records", ex);
        }
    }

    public T getById(long id) {
        return this.repository.findById(id).orElseThrow(() -> new NotFoundException(id));
    }

    public T save(T record) {
        try {
            return this.repository.save(record);
        } catch (RuntimeException ex) {
            throw new DatabaseOperationException("fail to save record", ex);
        }
    }

    public long count() {
        return this.repository.count();
    }

    public boolean delete(long id) {
        try {
            this.repository.deleteById(id);
            return true;
        } catch (RuntimeException ex) {
            throw new DatabaseOperationException("fail to delete the record with id:" + id, ex);
        }
    }

    public boolean softDelete(long id) {
        T obj = getById(id);
        obj.setDeleted(true);
        try {
            repository.save(obj);
            return true;
        } catch (RuntimeException ex) {
            throw new DatabaseOperationException("fail to soft delete the record with id:" + id, ex);
        }
    }

    protected Pageable getPageable(int page, int size, String field, Sort.Direction direction) {
        if (page < 1) { // no paging
            page = 1;
            size = Integer.MAX_VALUE;
        }
        int springDataPage = page - 1; // spring pagination start from 0
        return field == null ? PageRequest.of(springDataPage, size) : PageRequest.of(springDataPage, size, Sort.by(direction, field));
    }

    protected Pageable getPageable(int page, int size) {
        return getPageable(page, size, "id", Sort.Direction.DESC);
    }

    protected static String fuzzy(String v){
        return "%" + v + "%";
    }

}
